﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace Nextworks.Util.Collections
{
    public class BiDirectionalDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        #region Private Fields
        private Dictionary<TKey, TValue> _forward = new Dictionary<TKey, TValue>();
        private Dictionary<TValue, TKey> _backward = new Dictionary<TValue, TKey>();
        #endregion

        #region IDictionary<TKey,TValue> Members
        public void Add(TKey key, TValue value)
        {
            _forward.Add(key, value);
            _backward.Add(value, key);
        }
        public bool ContainsKey(TKey key)
        {
            return _forward.ContainsKey(key);
        }
        public ICollection<TKey> Keys
        {
            get { return _forward.Keys; }
        }
        public bool Remove(TKey key)
        {
            _backward.Remove(_forward[key]);
            return _forward.Remove(key);
        }
        public bool TryGetValue(TKey key, out TValue value)
        {
            return _forward.TryGetValue(key, out value);
        }
        public ICollection<TValue> Values
        {
            get { return _forward.Values; }
        }
        public TValue this[TKey key]
        {
            get { return _forward[key]; }
            set { _forward[key] = value; }
        }
        #endregion

        #region ICollection<KeyValuePair<TKey,TValue>> Members
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            ((ICollection<KeyValuePair<TKey, TValue>>)_forward).Add(item);
            ((ICollection<KeyValuePair<TValue, TKey>>)_backward).Add(new KeyValuePair<TValue, TKey>(item.Value, item.Key));
        }
        public void Clear()
        {
            ((ICollection<KeyValuePair<TKey, TValue>>)_forward).Clear();
            ((ICollection<KeyValuePair<TValue, TKey>>)_backward).Clear();
        }
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return ((ICollection<KeyValuePair<TKey, TValue>>)_forward).Contains(item);
        }
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            ((ICollection<KeyValuePair<TKey, TValue>>)_forward).CopyTo(array, arrayIndex);
        }
        public int Count
        {
            get { return ((ICollection<KeyValuePair<TKey, TValue>>)_forward).Count; }
        }
        public bool IsReadOnly
        {
            get { return ((ICollection<KeyValuePair<TKey, TValue>>)_forward).IsReadOnly; }
        }
        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            _backward.Remove(item.Value);
            return ((ICollection<KeyValuePair<TKey, TValue>>)_forward).Remove(item);
        }
        #endregion

        #region IEnumerable<KeyValuePair<TKey,TValue>> Members
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return ((IEnumerable<KeyValuePair<TKey, TValue>>)_forward).GetEnumerator();
        }
        #endregion

        #region IEnumerable Members
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _forward.GetEnumerator();
        }
        #endregion

        #region Public Methods for Reverse Lookup
        public bool ContainsValue(TValue value)
        {
            return _backward.ContainsKey(value);
        }
        public TKey ReverseLookup(TValue value)
        {
            return _backward[value];
        }
        #endregion
    }
}
